import { FMVCS } from "../../fgui/fmvc/FMVCS";
import GameMainCtrl from "./GameMainCtrl";
import { GlobalEvent } from "../global/Global";
import Star from "../component/star/Star";
import EventSystem from "../../core/EventSystem";
import GameMainData from "./GameMainData";
import { ConstDefine } from "../common/ConstDefine";
import PlayerCtrl from "../player/PlayerCtrl";

export default class GameMainView extends FMVCS.FView {
    /** 星星父节点 */
    private _starContent: fgui.GComponent = null;

    /** 数据类 */
    private _data: GameMainData = null;

    /** 当前关卡配置 */
    private _curCfg: ConstDefine.Config.StarConfig = null;

    /** 当前选择的类型 */
    private _chooseType: number = -1;

    /** 星星选择列表 */
    private _answerList: fgui.GList = null;

    /** 当前选择的星星 */
    private _curSelStar: fgui.GButton = null;

    /** 上一次选择的星星 */
    private _preSelStar: fgui.GButton = null;

    /** 星星列表 */
    private _starList: {[index: number]: Star} = {};

    /** 星星动画数量 */
    private _starActionNum: number = 0;

    /** 模式 */
    private _pattern: ConstDefine.GameMain.Pattern = 0;

    clickHandlers() {
        return [
            [this._views[`btnSetting`], this.onBtnSetting, this],
        ];
    }

    onBtnSetting() {
        EventSystem.emit(GlobalEvent.UIListenID.UI_BtnSetting_Click);
    }

    onOpenCallBack() {
        this._data = GameMainCtrl.data;
        this._curCfg = this._data.getCurConfig();
        this._starContent = this._views[`starContent`];
        this._pattern = this._data.vo.pattern;
        this.rigisterEventListener();
        this.initStar();
        this.initAnswerList();
        this.checkGuide();
    }

    rigisterEventListener(){
        EventSystem.on(GlobalEvent.UIListenID.UI_FinishOneGuideStep, this.onGuideStepFinish, this);
    }

    initStar() {
        this._data.vo.starNum = {};
        this._data.vo.allStar = 0;
        let map = this._data.vo.map;
        if (map) {
            for (let i = 0; i < map.length; ++i) {
                let index = map[i][1];
                if(!this._starList[index] || this._data.getIsEdit()){
                    let star = this.createStar() as Star;
                    this._starContent.addChild(star);
                    let starType = map[i][0];
                    let offsetx = 0;
                    let offsety = 0;
                    if(this._pattern == ConstDefine.GameMain.Pattern.normal){
                        if(this._curCfg.offset){
                            offsetx = this._curCfg.offset[0];
                            offsety = this._curCfg.offset[1];
                        }
                    }
                    star.setPosByIndex(index, offsetx, offsety);
                    
                    star.onClick(this.onStarClick, this);
                    star.setStarTypeImg(starType);
                    star.index = index;
    
                    this._starList[index] = star;

                    let starNum = this._data.vo.starNum;
                    if(!starNum[starType]){
                        starNum[starType] = 0;
                    }
                    starNum[starType]++;
                    this._data.vo.starNum = starNum;

                    this._data.vo.allStar++;
                }else{
                    console.error(`index有重复，请检查配置: ${index}`);
                }
            }
            this.onFlush();
        }
    }

    onStarClick(event: fgui.Event){
        let star = event.currentTarget.$gobj as Star;
        if(!this.getCanAnswer()) return;
        if(this._chooseType != -1 && star.type != this._chooseType){
            let stepCost = -1;
            if(this._data.getIsEdit()){
                stepCost = 1;
            }
            this._data.vo.step += stepCost;
            this.runStarAction(star, this._chooseType).then(() => {
                this.searchStar(star);
            });
            this.onFlush(`step`);
        }
    }

    createStar() {
        return Star.createStar();
    }

    searchStar(star: Star){
        let serchPath1 = [-7, -14, 14, 7];
        let serchPath2 = [-6, 8];
        let serchPath3 = [-8, -14, -7, 6, 14, 7];
        let pos = star.index;
        let searchPos = (sPos: number) => {
            let searchStar = this._starList[sPos];
            let isTarget = searchStar && searchStar.type != star.type && star.lastType == searchStar.type;
            if(isTarget){
                this.runStarAction(searchStar, this._chooseType).then(() => {
                    this.searchStar(searchStar);
                });
            }
            return isTarget;
        }
        if(Math.floor(pos / 7) % 2 === 0){
            for(let i = 0; i < serchPath1.length; ++i){
                searchPos(pos + serchPath1[i]);
            }
            if((pos + 1) % 7 !== 0){
                for(let i = 0; i < serchPath2.length; ++i){
                    searchPos(pos + serchPath2[i]);
                }
            }
        }else{
            for(let i = 0; i < serchPath3.length; ++i){
                searchPos(pos + serchPath3[i]);
            }
        }
    }

    runStarAction(star: Star, type: number): Promise<any> {
        return new Promise((res, rej) => {
            this._starActionNum++;
            this._data.vo.starNum[star.type]--;
            star.runStarActionAndChange(type, res).then(() => {
                this._starActionNum--;
                this._data.vo.starNum[type]++;
                if(this._starActionNum === 0){
                    if(this._data.vo.starNum[type] == this._data.vo.allStar){
                        switch(this._pattern){
                            case ConstDefine.GameMain.Pattern.create: {
                                this._data.curConfig.step = this._data.vo.step;
                                EventSystem.emit(GlobalEvent.GameEventID.GameMapRelease, this._data.curConfig);
                                break;
                            }
                            case ConstDefine.GameMain.Pattern.rivisions: {
                                this._data.curConfig.step = this._data.vo.step;
                                EventSystem.emit(GlobalEvent.GameEventID.GameMapRivisionsRelease, this._data.curConfig);
                                break;
                            }
                            default: {
                                this.onGameResult(true);
                            }
                        }
                        return;
                    }
                    if(this._data.vo.step == 0){
                        if(this._data.getIsNormal()){
                            this.onGameResult(false);
                        }
                        return;
                    }
                }
            }).catch(rej);
        });
    }

    initAnswerList(){
        this._answerList = this._views[`answerList`].asList;
        this._answerList.itemRenderer = this.onItemRender.bind(this);
        if(this._data.vo){
            this._answerList.numItems = this._data.vo.answerStar.length;
        }
    }

    onItemRender(index: number, star: Star){
        if(this._data.vo){
            let type = this._data.vo.answerStar[index];
            star.setStarTypeImg(type);
            star.onClick(this.onAnswerStarClick, this);
            star.index = index;
        }
    }

    onAnswerStarClick(event: fgui.Event){
        let star = event.currentTarget.$gobj as Star;
        if(this._curSelStar == star) return;
        if(!this.getCanAnswer()) return;

        this._chooseType = star.type;
        this._preSelStar = this._curSelStar;
        this._curSelStar = star;
        
        if(this._preSelStar)
            this._preSelStar.setScale(1, 1);
        if(this._curSelStar)
            this._curSelStar.setScale(1.3, 1.3);
    }

    onGameResult(isWin: boolean){
        GameMainCtrl.gameResult(isWin);
        this.onClose();
    }

    getCanAnswer(){
        return this._starActionNum === 0;
    }

    checkGuide(){
        if(!this._data.getIsNormal()) return;
        if(PlayerCtrl.data.vo.maxLevel == 0){
            let guideItemData: ConstDefine.Guide.EventItemData = {
                id: 0,
                step: 0,
                obj: this._answerList._children[0].asButton,
            }
            EventSystem.emit(GlobalEvent.UIListenID.UI_GuideView_Open, guideItemData);
        }
    }

    onGuideStepFinish(info: ConstDefine.Guide.EventItemData){
        let guideId = info.id;
        let nextStep = info.step + 1;
        let obj = info.obj;
        let haveGuide = false;
        if(guideId === 0){
            switch(nextStep){
                case 1: {
                    obj = this._starList[101];
                    break;
                }
                case 2: {
                    obj = this._starList[73];
                    break;
                }
            }
            if(obj != info.obj)
                haveGuide = true;
        }
        if(haveGuide){
            let guideItemData: ConstDefine.Guide.EventItemData = {
                id: guideId,
                step: nextStep,
                obj: obj,
            }
            EventSystem.emit(GlobalEvent.UIListenID.UI_GuideView_Open, guideItemData);
        }
    }

    onFlush(type: string = `all`){
        switch(type){
            case `all`: {
                this._updateLblStep();
                this._updateLblLevel();
                this._updateHelpLayout();
                this._updateLblRelease();
                break;
            }
            case `step`: {
                this._updateLblStep();
                break;
            }
        }
    }

    private _updateLblStep(){
        let str = this._data.getIsEdit() ? `步数: ` : `剩余步数: `;
        str = str + this._data.vo.step;
        this._views[`lblStep`].asLabel.text = str;
    }

    private _updateLblLevel(){
        let lbl = this._views[`lblLevel`].asLabel;
        lbl.text = `关卡: `;
        if(this._data.getIsNormal()){
            lbl.text += (this._data.vo.level + 1);
        }else{
            lbl.text += this._data.vo.mapName;
        }
    }

    private _updateHelpLayout(){
        this._views[`helpLayout`].visible = this._data.getIsNormal();
    }

    private _updateLblRelease(){
        this._views[`lblReleaseTips`].visible = this._data.getIsEdit();
    }
}